//
//  AppController.m
//  WorkBreak
//
//  Created by Wei Nan Li on 11/7/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "AppController.h"

@implementation AppController

@synthesize alertInterval;
@synthesize restTime;

#pragma mark Menu Creation
- (NSMenu *) createMenu {
	NSZone *menuZone = [NSMenu menuZone];
	NSMenu *menu = [[NSMenu allocWithZone:menuZone] init];
		
	statusMenuItem = [menu addItemWithTitle:@"Starting up..." 
							   action:nil 
						keyEquivalent:@""];
	[statusMenuItem setEnabled:NO];
	
	[menu addItem:[NSMenuItem separatorItem]];
	
	preferencesItem = [menu addItemWithTitle:@"Preferences"
									  action:@selector(showPreferences)
							   keyEquivalent:@""];
	
	[preferencesItem setTarget:self];
	[menu addItem:[NSMenuItem separatorItem]];	
	timerSwitchItem = [menu addItemWithTitle:@"Disable me"
									  action:@selector(disableOrEnableMe)
							   keyEquivalent:@""];
	
	[timerSwitchItem setTarget:self];
	forceModeItem  = [menu addItemWithTitle:@"Force Mode"
									 action:@selector(switchForceMode)
							  keyEquivalent:@""];

	[forceModeItem setTarget:self];	
	[menu addItem:[NSMenuItem separatorItem]];	
	quitItem = [menu addItemWithTitle:@"Quit" 
							   action:@selector(quitMe) 
						keyEquivalent:@""];

	[quitItem setTarget:self];	
	[menu setAutoenablesItems:NO];
	
	return menu;
}

#pragma mark Setting Methods
- (void)showPreferences {
	NSScreen* mainScreen = [NSScreen mainScreen];
	NSRect winRect = [mainScreen frame];	
	
	// position the window in the middle of the screen
	NSPoint pos;
	pos.x = winRect.size.width*(1 - 0.618);
	pos.y = winRect.size.height*(1 - 0.618);
	
	[prefPanel setFrameOrigin:pos];
	[prefPanel viewsNeedDisplay];
	[prefPanel makeKeyAndOrderFront:self];
}

- (void)switchForceMode {	
	[forceModeItem setState:[forceModeItem state] == NSOnState? NSOffState : NSOnState];	
}

- (void)disableOrEnableMe {
	if (myStatus == YES) {
		if (noteCycleTimer != nil && [noteCycleTimer isValid])
			[noteCycleTimer invalidate];
		
		if (restCycleTimer != nil && [restCycleTimer isValid]) {
			[restCycleTimer invalidate];
			//[self probeRestTimerCycleState];
		}
		
		if (restProgressCycleTimer != nil && [restProgressCycleTimer isValid])
			[restProgressCycleTimer invalidate];
		
		[self cleanupScreen];		
		
		[timerSwitchItem setTitle:@"Enable me"];
		[statusMenuItem setTitle:@"Disabled"];
		myStatus = NO;
	} else {
	 	if (restCycleTimer == nil || ![restCycleTimer isValid]) {
			[self registerRestCycleTimer:[alertIntervalField floatValue]*60.0];
			//[self probeRestTimerCycleState];
		}
		[timerSwitchItem setTitle:@"Disable me"];
		myStatus = YES;
	}
}

- (void)quitMe {
	[NSApp terminate:self];
}


- (IBAction)cancel:(id)sender {
	[prefPanel close];
}

- (IBAction)settingChanged:(id)sender {	
	// stop the timer
	if (restCycleTimer != nil && [restCycleTimer isValid]) {
		[restCycleTimer invalidate];
	}
	
	if (restProgressCycleTimer != nil && [restProgressCycleTimer isValid])
		[restProgressCycleTimer invalidate];	
	
	[[NSUserDefaults standardUserDefaults] setFloat:[alertIntervalField floatValue] 
											 forKey:workIntervalKey];
	[[NSUserDefaults standardUserDefaults] setFloat:[restTimeField floatValue] 
											 forKey:restIntervalKey];
	/*
	 if ([alertIntervalField floatValue] < MIN_WORK_INTERVAL) {
	 [alertIntervalField setFloatValue:alertInterval];
	 }
	 
	 if ([restTimeField floatValue] < MIN_REST_INTERVAL) {
	 [restTimeField setFloatValue:restTime];
	 }*/
	
	//if ([alertIntervalField floatValue] >= [restTimeField floatValue]) {
		[self setAlertInterval: [alertIntervalField floatValue]];
		[self setRestTime: [restTimeField floatValue]];
	//} else {
	//	[alertIntervalField setFloatValue:alertInterval];
	//	[restTimeField setFloatValue:restTime];
	//}
	
	[self cleanupScreen];
	[self registerRestCycleTimer: [alertIntervalField floatValue]*60.0];
	[prefPanel close];
	
	//counter = [alertIntervalField floatValue]*60.0;

	//NSLog(@"alertInterval: %f", [self alertInterval]);
	//NSLog(@"restTime: %f", [self restTime]);
}

#pragma mark View Creation

- (void) countdownTimer {
	if (myStatus == YES) {
		[statusMenuItem setTitle:[NSString stringWithFormat:@"Time left to next break: %.1f mintues", counter/60.0]];
	}
	
	if (counter <= 0.0) {		
		//[self setAlertInterval: [prefs defaultWorkInterval]];
		counterStartValue = counter = [prefs defaultWorkInterval] * 60;
		prevPos = [NSEvent mouseLocation];
		//NSLog(@"countdown reset");
		return;
	}
		
	// put all timer to idle
	//[self probeRestTimerCycleState];
	currPos = [NSEvent mouseLocation];

	//NSLog(@"diff_posX: %f, diff_posY: %f", fabs(currPos.x - prevPos.x), 
	//	  fabs(currPos.y - prevPos.y));	

	if  ((counterStartValue - counter >= 60.0) && [restCycleTimer isValid]
		 && fabs(currPos.x - prevPos.x) <= 20.0 
		 && fabs(currPos.y - prevPos.y) <= 20.0 
		 && isIdle == NO
		 && [restCycleTimer isValid]) {
		//NSLog(@"idle...");
		[restCycleTimer invalidate];
		prevPos = [NSEvent mouseLocation];
		isIdle = YES;		
		return;
	}
		
	if (isIdle == YES && counter < counterStartValue) {
		counter++;
	}
		
	if (isIdle == YES && (fabs(currPos.x - prevPos.x) >= 20.0 
						  || fabs(currPos.y - prevPos.y) >= 20.0)) {
		//NSLog(@"wakeup");
		[self registerRestCycleTimer:counter];
		isIdle = NO;
	}
	
	if (isIdle == NO) {
		--counter;
		prevPos = [NSEvent mouseLocation];
		//NSLog(@"%f,", counter);
	}

}

- (void) registerRestCycleTimer:(float) intervalInSecond {		
	//NSLog(@"alertInterval: %f", [self alertInterval]);
	//NSLog(@"restTime: %f", [self restTime]);
	counterStartValue = counter = intervalInSecond;
	restCycleTimer = [[NSTimer timerWithTimeInterval:intervalInSecond
											  target:self
											selector:@selector(fireRestCycle)
											userInfo:self
											 repeats:NO] retain];		
	
	[[NSRunLoop mainRunLoop] addTimer:restCycleTimer forMode:NSDefaultRunLoopMode];
}

- (void) fireNoteCycle {
	[mainView setBarLength: 0.0];
	
	restProgressCycleTimer = [[NSTimer timerWithTimeInterval:([self restTime] * 60)/INDICATOR_STEP
													  target:self
													selector:@selector(fireRestProgressCycle)
													userInfo:self
													 repeats:YES] retain];	
	[onSound play];	
	[[mainView window] setCanHide:NO];
	[[mainView window] makeKeyAndOrderFront:self];
	[masker setupMaskForAllScreens];
	[masker maskAllScreens];
	
	[[NSRunLoop mainRunLoop] addTimer:restProgressCycleTimer forMode:NSDefaultRunLoopMode];
	
}

- (void) fireRestCycle {
	noteCycleTimer = [[NSTimer timerWithTimeInterval:10
											  target:self
											selector:@selector(fireNoteCycle)
											userInfo:self
											 repeats:NO] retain];
	
	[[NSRunLoop mainRunLoop] addTimer:noteCycleTimer forMode:NSDefaultRunLoopMode];
	
	if ([forceModeItem state] == NSOnState) {
		[forceModeItem setEnabled:NO];
		[timerSwitchItem setEnabled:NO];
		[quitItem setEnabled:NO];
	}
	
	[GrowlApplicationBridge notifyWithTitle:@"Work Break Reminder"
								description:@"You should have a rest soon..."
						   notificationName:@"WorkBreak"
								   iconData:nil
								   priority:1
								   isSticky:NO
							   clickContext:nil];
	
	if ([forceModeItem state] != NSOnState) {
		[GrowlApplicationBridge notifyWithTitle:@"Work Break Reminder"
									description:@"Double click me to skip"
							   notificationName:@"WorkBreak"
									   iconData:nil
									   priority:1
									   isSticky:NO
								   clickContext:@"growlNoteClicked"];
	}
	
}

- (void) fireRestProgressCycle {
	[restCycleTimer invalidate];
	[statusMenuItem setTitle:@"Have a rest please..."];
	// rest time expired
	if ([mainView barLength] == INDICATOR_STEP) {
		[restProgressCycleTimer invalidate];
		[self cleanupScreen];
		[offSound play];
		[forceModeItem setEnabled:YES];
		[timerSwitchItem setEnabled:YES];
		[quitItem setEnabled:YES];
		// now we refresh the work cycle timer in case user changes the alertInterval
		[self registerRestCycleTimer: [alertIntervalField floatValue]*60.0];
	}
	else  {
		[mainView setBarLength: [mainView barLength] + 1];	
		// refresh the progress bar
		[mainView setNeedsDisplay:YES];	
	}
}

- (void) cleanupScreen {
	[[mainView window] orderOut:self];
	[masker unmaskAllScreens];
	[masker destroyMaskForAllScreens];
}

#pragma mark System Functions

- (void) dealloc {
	[onSound dealloc];
	[offSound dealloc];
	[super dealloc];
}

#pragma mark Delegate Methods
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
	
	[GrowlApplicationBridge setGrowlDelegate:self];
	
	[self setAlertInterval: [prefs workInterval]];
	[self setRestTime: [prefs restInterval]];
	
	masker = [[WBScreenMasker alloc] retain];
	[masker init];
	
	onSound = [NSSound soundNamed:@"On"];
	offSound = [NSSound soundNamed:@"Off"];
	
	NSMenu *menu = [self createMenu];
	
	statusItem = [[[NSStatusBar systemStatusBar]
				   statusItemWithLength:NSSquareStatusItemLength] retain];
	[statusItem setMenu:menu];
	[statusItem setHighlightMode:YES];
	[statusItem setToolTip:@"Work Break"];
	[statusItem setImage:[NSImage imageNamed:@"moof-tray"]];
	
	[menu release];
	
	[self registerRestCycleTimer: [alertIntervalField floatValue]*60.0];
	//[self probeRestTimerCycleState];
	
	prevPos = [NSEvent mouseLocation];
	isIdle = NO;
	countdownTimer = [[NSTimer timerWithTimeInterval:1
											  target:self
											selector:@selector(countdownTimer)
											userInfo:self
											 repeats:YES] retain];
	[[NSRunLoop mainRunLoop] addTimer:countdownTimer forMode:NSDefaultRunLoopMode];
	myStatus = YES;
}

//Disable Application Close
/*
 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
 return NSTerminateCancel;
 }
 */

#pragma mark ---   Growl Delegate Methods   ---

- (void) growlNotificationWasClicked:(id)clickContext
{
	//[self activateIgnoringOtherApps:YES];
	
	//NSLog(@"growl note clicked");	
	[self disableOrEnableMe];
	[self disableOrEnableMe];
	counter = [alertIntervalField floatValue]*60.0;
	[GrowlApplicationBridge notifyWithTitle:@"Work Break Reminder"
								description:@"You have chosen to skip workbreak this time."
						   notificationName:@"WorkBreak"
								   iconData:nil
								   priority:1
								   isSticky:NO
							   clickContext:nil];
	[timerSwitchItem setEnabled:YES];
	[forceModeItem setEnabled:YES];
	[quitItem setEnabled:YES];	
	
}

- (NSDictionary *) registrationDictionaryForGrowl
{
	NSArray *notifications = [NSArray arrayWithObject: @"WorkBreak"];
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
						  notifications, GROWL_NOTIFICATIONS_ALL,
						  notifications, GROWL_NOTIFICATIONS_DEFAULT, nil];
	
	return dict;
}

@end
